package cn.learn.httpclient;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;

/**
 * 请求连接工具类
 * httpClient单例的时候速度更快
 * okHttp 多实例的时候速度更快
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2021年08月30日17:17
 */
@Slf4j
public enum HttpClientUtil {
    /**
     * 单例
     */
    INSTANCE;

    private CloseableHttpClient httpClient = null;

    private RequestConfig requestConfig = null;

    HttpClientUtil() {
        httpClient = HttpClients.custom()
                .disableAutomaticRetries()
                .build();

        requestConfig = RequestConfig.custom()
                .setConnectTimeout(10000)
                .setSocketTimeout(10000)
                .setConnectionRequestTimeout(10000)
                .build();
    }

    public String doPost(String url, String contentMap) {
        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        // 设置请求头部
        post.setHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8");
        StringEntity requestEntity = new StringEntity(contentMap, StandardCharsets.UTF_8);
        // post.addHeader("token","token");
        post.setEntity(requestEntity);
        return execute(post, contentMap);
    }

    public String doSslPost(String url, String contentMap, String certificateUrl, String passKey) {
        SSLConnectionSocketFactory sslsf  = sslCertificate(certificateUrl, passKey);
        CloseableHttpClient        httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        HttpPost post = new HttpPost(url);
        post.setHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8");
        StringEntity requestEntity = new StringEntity(contentMap, StandardCharsets.UTF_8);
        post.setEntity(requestEntity);

        try {
            CloseableHttpResponse response = httpClient.execute(post);
            // 获取response的body部分
            HttpEntity entity = response.getEntity();
            // 响应状态
            StatusLine statusLine = response.getStatusLine();
            return EntityUtils.toString(entity);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 执行请求
     * 创建 CloseableHttpClient对象或CloseableHttpAsyncClient对象，前者同步，后者为异步
     */
    private String execute(HttpPost post, String contentMap) {
        // 发送请求并接收返回数据
        try (CloseableHttpResponse response = httpClient.execute(post)) {
            // 获取response的body部分
            HttpEntity entity = response.getEntity();
            // 响应状态
            StatusLine statusLine = response.getStatusLine();
            return EntityUtils.toString(entity);
        } catch (IOException e) {
            if (e instanceof SocketTimeoutException) {
                log.error("超过等待设定[{}]ms，响应超时：{}", requestConfig.getSocketTimeout(), e.getMessage());
            } else if (e instanceof ConnectTimeoutException) {
                log.error("超过请求连设定[{}]ms,接超时：{}", requestConfig.getConnectTimeout(), e.getMessage());
            } else {
                log.error("请求异常：{}", e.getMessage(), e);
            }
            log.error("手动入库参数：{}", contentMap);
            return null;
        }
    }


    private SSLConnectionSocketFactory sslCertificate(String certificateUrl, String passKey) {
        try (InputStream inputStream = HttpClientUtil.class.getClassLoader().getResourceAsStream(certificateUrl)) {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(inputStream, passKey.toCharArray());

            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, passKey.toCharArray()).build();
            // 只允许TLSv1协议
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext.getSocketFactory(),
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            return sslsf;
        } catch (KeyStoreException e) {
            log.error("生成秘钥库异常：{}", e.getMessage());
        } catch (CertificateException e) {
            log.error("加载的证书有问题：{}", e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            log.error("加载的证书算法异常：{}", e.getMessage());
        } catch (IOException e) {
            log.error("加载证书流有问题：{}", e.getMessage());
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("创建证书失败！");
    }

}
